namespace GYLite{
    export type SeparatorResult = {error:SysError,width:number,height:number,left:number,right:number,top:number,bottom:number,indices:number[],vertices:number[],uvs:number[]};
    class Line{
        public startPoint:Point;
        public endPoint:Point;
        /**是否属于分割线*/public isSeparateLine:boolean;
        /**
         * @param p1 起点
         * @param p2 终点
         * @param isSeparate 是否属于分割线
        */
        constructor(p1:Point,p2:Point,isSeparate:boolean = false)
        {
            let s = this;
            s.startPoint = p1;
            s.endPoint = p2;
            s.isSeparateLine = isSeparate;
        }                
        public isCap(pt:Point):boolean
        {
            return this.startPoint == pt || this.endPoint == pt;
        }
        public isConcat(cLine:Line):boolean
        {
            return this.isCap(cLine.startPoint) || this.isCap(cLine.endPoint);
        }
    }
    class Point{
        public x:number;
        public y:number;
        public index:number;
        constructor(x:number=0,y:number=0,index:number=0)
        {
            let s= this;
            s.x = x;
            s.y = y;
            s.index = index;
        }        
    }
    export class Separator{          
        /**分割三角形
         * @param path 路径数组 [x1,y1,x2,y2……]
         * @param check 是否检测路径存在相交点
         * @param createUV 是否生成uv数据，生成的uv用于纹理填充 默认false         
         * @param offsetX 纹理偏移量x
         * @param offsetY 纹理偏移量y
         * @param fillWidth 填充纹理的宽度 默认100
         * @param fillHeight 填充纹理的高度 默认100
         * @param matrix 纹理的matrix变换
         * @param repeat 是否重复填充 默认false
        */
        public static separate(path:number[],check:boolean=true,createUV:boolean=false,offsetX:number=0,offsetY:number=0,fillWidth:number=100,fillHeight:number=100,matrix:egret.Matrix=null,repeat:boolean=false):SeparatorResult
        {
            let i:number,len:number,j:number,len2:number,k:number,len3:number;
            let startCol:number,startRow:number;
            let lines:Line[];
            let p1:Point,p2:Point;
            let line:Line;
            let result:SeparatorResult;
            let cLine:Line;            
            let triangleLine:Line;
            let preLine:Line,nextLine:Line;
            let minArea:number,area:number;
            let findTri:boolean;
            let triangleLineInd:number;            

            let arr:number[],arr2:number[];
            let minX:number,minY:number,maxX:number,maxY:number;
            let ax:number,ay:number,bx:number,by:number,cx:number,cy:number;
            let rectX:number,rectY:number,x:number,y:number;
            let u:number,v:number;
            let indA:number,indB:number,indC:number;            
            let newIndices:number[],newVertices:number[];
            
            result = {error:null,indices:[],vertices:[],uvs:null,left:Number.MAX_VALUE,right:Number.MIN_VALUE,top:Number.MAX_VALUE,bottom:Number.MIN_VALUE,width:0,height:0};
            if(path == null || path.length < 6 || path.length % 2 == 1)
            {
                result.error = SysError.SEPARATOR_NUM_NOT_ENOUGH.throwError([path?path.length / 2:0]);
                return result;
            }
            if(check)
            {
                len = path.length - 4;
                for(i=0;i<len;i+=2)
                {                
                    len2 = path.length - 2;
                    for(j=i+4;j<len2;j+=2)
                    {                   
                        if(path[0] == path[path.length - 2] && path[1] == path[path.length - 1])
                            continue;
                        if(PositionUtil.intersect(path[i],path[i+1],path[i+2],path[i+3],path[j],path[j+1],path[j+2],path[j+3]))
                        {
                            result.error = SysError.SEPARATOR_PATH_CROSS.throwError([i/2,path[i],path[i+1],(i+2)/2,path[i+2],path[i+3],j/2,path[j],path[j+1],(j+2)/2,path[j+2],path[j+3]]);
                            return result;
                        }                    
                    }
                }
            }            

            //判断路径是否顺时针，不是则反向操作一下
            let clock:number;
            clock = PositionUtil.clockwisePath(path);
            if(clock == 0)  
            {
                result.error = SysError.SEPARATOR_PATH_IS_LINE.throwError([path[path.length - 6],path[path.length - 5],path[path.length - 4],path[path.length - 3],path[path.length - 2],path[path.length - 1]]);
                return result;
            }
            if(clock < 0)
            {//逆时针，反过输入让lines保持顺时针
                arr = [];
                arr.push(path[0],path[1]);
                len = path.length;
                for(i=len-2;i>0;i-=2)                
                    arr.push(path[i],path[i+1]);                
                path = arr;
            }            

            //生成线条队列
            lines = [];       
            p1 = new Point(path[0], path[1], 0);
            if(path[0] < result.left)
                result.left = path[0];
            if(path[0] > result.right)
                result.right = path[0];
            if(path[1] < result.top)
                result.top = path[1];
            if(path[1] > result.bottom)
                result.bottom = path[1];
            result.vertices.push(p1.x,p1.y);
            
            len = path.length;
            for(i=2;i<len;i+=2)
            {
                p2 = new Point(path[i], path[i+1], i/2);
                lines.push(new Line(p1,p2));                                                                      
                p1 = p2;
                result.vertices.push(p2.x,p2.y);
                if(p2.x < result.left)
                    result.left = p2.x;
                else if(p2.x > result.right)
                    result.right = p2.x;
                if(p2.y < result.top)
                    result.top = p2.y;
                else if(p2.y > result.bottom)
                    result.bottom = p2.y;
            }
            result.width = result.right - result.left;
            result.height = result.bottom - result.top;

            lines.push(new Line(p2,lines[0].startPoint));
            
            while(lines.length > 0)
            {
                if(line == null)
                    line = lines.shift();
                preLine = line;
                minArea = Number.MAX_VALUE;
                triangleLine = null;
                findTri = false;
                len = lines.length;
                for(i=0;i<len;++i)
                {
                    cLine = lines[i];          
                    nextLine = i == len-1?line:lines[i+1];
                    //当前线条与前后线条形成三角形
                    if(preLine.endPoint == cLine.startPoint && cLine.endPoint == nextLine.startPoint && nextLine.endPoint == preLine.startPoint)
                    {
                        findTri = true;
                        if(nextLine != line)
                            lines.splice(i + 1, 1);
                        lines.splice(i, 1);
                        if(preLine != line)
                            lines.splice(i - 1, 1);
                        break;
                    }                    
                    if(i == len - 1)
                        break;//最后一条线不做距离检测                    
                    area = MathUtil.calTriangleArea(line.startPoint.x,line.startPoint.y,line.endPoint.x,line.endPoint.y,cLine.endPoint.x,cLine.endPoint.y, true);                    
                    if(area <= 0)
                        continue;
                    if(minArea > area)
                    {
                        minArea = area;
                        triangleLine = cLine;   
                        triangleLineInd = i;
                    }     
                    preLine = cLine;
                }
                //直接找到三角形
                if(findTri)
                {
                    if(preLine == line || nextLine == line)
                        line = null;
                    result.indices.push(preLine.startPoint.index,cLine.startPoint.index,nextLine.startPoint.index);
                    if(lines.length == 0)
                        break;
                    continue;
                }                
                if(triangleLine == null)
                {
                    result.error = SysError.SEPARATOR_CANNOT_FINDNEAREST.throwError([line.startPoint.x,line.startPoint.y,line.startPoint.index,line.endPoint.x,line.endPoint.y,line.endPoint.index]);
                    return result;
                }

                //找到最近的分割点                
                if(triangleLine.endPoint == line.startPoint)
                {//line是triangleLine的下一条边
                    lines.splice(triangleLineInd, 1);
                    lines.unshift(new Line(line.endPoint, triangleLine.startPoint, true));                    
                    result.indices.push(line.startPoint.index,line.endPoint.index,triangleLine.startPoint.index);
                    
                }
                else if(triangleLine.startPoint == line.endPoint)
                {//triangleLine是line的下一条边
                    lines.splice(triangleLineInd, 1);
                    lines.unshift(new Line(line.startPoint, triangleLine.endPoint, true));
                    result.indices.push(line.startPoint.index,line.endPoint.index,triangleLine.endPoint.index);
                }
                else
                {//triangleLine跟line不相连，采用triangleLine.endPoint新增两条与line相连的边进行分割
                    preLine = lines[lines.length - 1];
                    nextLine = lines[0];
                    if(nextLine.isCap(triangleLine.endPoint))//是后邻边
                        lines.shift();                        
                    else
                        lines.unshift(new Line(triangleLine.endPoint,line.endPoint, true));
                    if(preLine.isCap(triangleLine.endPoint))//是前邻边，剔除当前存在的前邻边                
                        lines.pop();
                    else
                        lines.unshift(new Line(line.startPoint,triangleLine.endPoint, true));
                    
                    result.indices.push(line.startPoint.index,line.endPoint.index,triangleLine.endPoint.index);
                }
                line = null;
            }
            //根据repeat、fillWidth、fillHeight重新计算三角形与repeat分区的交集，得到新的三角形顶点数组（不共点），再计算出uv值            
            if(createUV)
            {
                let isMatrix:boolean;
                let r:number,b:number;
                isMatrix = matrix && (matrix.a != 1 || matrix.b != 0 || matrix.c != 0 || matrix.d != 1 || matrix.ty != 0 || matrix.tx != 0);
                r = offsetX + fillWidth;
                b = offsetY + fillHeight;
                if(isMatrix)
                {
                    x = offsetX + matrix.tx;
                    y = offsetY + matrix.ty;                                        
                    ax = matrix.a * r + matrix.c * offsetY + matrix.tx;
                    ay = matrix.d * offsetY + matrix.b * r + matrix.ty;
                    bx = matrix.a * r + matrix.c * b + matrix.tx;
                    by = matrix.d * b + matrix.b * r + matrix.ty;
                    cx = matrix.a * offsetX + matrix.c * b + matrix.tx;
                    cy = matrix.d * b + matrix.b * offsetX + matrix.ty;
                    arr = [x,y,ax,ay,bx,by,cx,cy];
                }
                else
                    arr = [offsetX,offsetY,r,offsetY,r,b,offsetX,b];                
                arr2 = [result.left,result.top,result.right,result.top,result.right,result.bottom,result.left,result.bottom];
                //判断填充是否能覆盖整个路径区域
                len = arr2.length;
                for(i=0;i<len;i+=2)
                {
                    x = arr2[i];
                    y = arr2[i+1];
                    if(!PositionUtil.isPointInShape(x,y,arr))
                        break;
                }
                if(i == len)
                {
                    //填充已经覆盖区域，直接变换顶点uv即可
                    result.uvs = [];
                    arr = result.vertices;
                    len = arr.length;
                    if(isMatrix)
                    {
                        matrix.invert();
                        // ax = -matrix.tx/fillWidth;
                        // ay = -matrix.ty/fillHeight;
                        for(i=0;i<len;i+=2)
                        {
                            // x = arr[i] % fillWidth;
                            // y = arr[i+1] % fillHeight;
                            // u = (x - offsetX) / fillWidth;
                            // v = (y - offsetY) / fillHeight;
                            // result.uvs[i] = matrix.a * u + matrix.c * v + ax;
                            // result.uvs[i + 1] = matrix.d * v + matrix.b * u + ay;
                            x = arr[i] - offsetX;
                            y = arr[i + 1] - offsetY;
                            u = matrix.a * x + matrix.c * y + matrix.tx;
                            v = matrix.d * y + matrix.b * x + matrix.ty;
                            result.uvs[i] = u / fillWidth;
                            result.uvs[i + 1] = v / fillHeight;
                        }                        
                    }
                    else
                    {
                        for(i=0;i<len;i+=2)
                        {                            
                            result.uvs[i] = (arr[i] % fillWidth) / fillWidth;
                            result.uvs[i + 1] = (arr[i+1] % fillHeight) / fillHeight;
                        }
                    }
                    
                    return result;
                } 
                //存在矩阵变换，对所有顶点做逆变换来填充
                if(isMatrix)                                                           
                    matrix.invert();
                    
                Separator.tempPointsD.length = 0;
                result.uvs = [];
                newIndices = [];
                newVertices = [];
                arr = result.indices;
                len = arr.length;
                for(i=0;i<len;i+=3)
                {   
                    indA = arr[i]*2;
                    ax = result.vertices[indA];
                    ay = result.vertices[indA+1];
                    indB = arr[i+1]*2;
                    bx = result.vertices[indB];
                    by = result.vertices[indB+1];
                    indC = arr[i+2]*2;
                    cx = result.vertices[indC];
                    cy = result.vertices[indC+1];
                    if(isMatrix)
                    {   
                        x = matrix.a * ax + matrix.c * ay + matrix.tx;
                        y = matrix.b * ax + matrix.d * ay + matrix.ty;
                        ax = x;
                        ay = y;
                        x = matrix.a * bx + matrix.c * by + matrix.tx;
                        y = matrix.b * bx + matrix.d * by + matrix.ty;
                        bx = x;
                        by = y;
                        x = matrix.a * cx + matrix.c * cy + matrix.tx;
                        y = matrix.b * cx + matrix.d * cy + matrix.ty;
                        cx = x;
                        cy = y;
                    }
                    minX = Math.min(ax,bx,cx);
                    maxX = Math.max(ax,bx,cx);
                    minY = Math.min(ay,by,cy);
                    maxY = Math.max(ay,by,cy);
                    startCol = Math.floor(minX / r);//列
                    len2 = Math.ceil(maxX / r);                    
                    startRow = Math.floor(minY / b);//行
                    len3 = Math.ceil(maxY / b);             
                    //三角形完全在矩形内，不需要调整顶点               
                    // if(len2 - startCol <= 1 && len3 - startRow <= 1)
                    // {
                    //     //不重复的模式，只取第一个填充
                    //     if(!repeat && (startCol != 0 || startRow != 0))
                    //      continue;
                    //     triNum = newVertices.length/2;
                    //     newIndices.push(triNum,triNum+1,triNum+2);
                    //     indA = newVertices.length;
                    //     newVertices.push(ax,ay,bx,by,cx,cy);

                    //     result.uvs[indA]=(ax - result.left)/fillWidth - startCol;
                    //     result.uvs[indA+1]=(ay - result.top)/fillHeight - startRow;
                    //     result.uvs[indA+2]=(bx - result.left)/fillWidth - startCol;
                    //     result.uvs[indA+3]=(by - result.top)/fillHeight - startRow;
                    //     result.uvs[indA+4]=(cx - result.left)/fillWidth - startCol;
                    //     result.uvs[indA+5]=(cy - result.top)/fillHeight - startRow;                                      
                    //     continue;
                    // }
                        
                    Separator.tempPointsC.length = Separator.tempPointsB.length = 0;
                    Separator.tempPointsB.push(ax,ay,bx,by,cx,cy);
                    for(k = startRow;k<len3;++k)
                    {
                        rectY = offsetY + k * b;
                        for(j = startCol;j<len2;++j)
                        {
                            if(!repeat && (k != 0 || j != 0))//不重复的模式，只取第一个填充
                            continue;
                            rectX = offsetX + j * r;
                            Separator.tempPointsC.length = Separator.tempPointsA.length = 0;
                            Separator.tempPointsA.push(rectX,rectY,rectX+fillWidth,rectY,rectX+fillWidth,rectY+fillHeight,rectX,rectY+fillHeight);
                            // console.log("start:(" + i + "," + k + "," + j + ")","tri:"+Separator.tempPointsB,"rect:"+Separator.tempPointsA);                            
                            // if(i == 0  && k == 1 && j == 2)
                            // debugger;
                            Separator.triangleCutRect(Separator.tempPointsA,Separator.tempPointsB,Separator.tempPointsC);
                            // if(k== 0 && j == 0 && Separator.tempPointsC.length == 0)
                            // console.log("length:0",i,k,j);
                            if(repeat && Separator.tempPointsC.length % 6 != 0)
                            debugger;
                            if(Separator.tempPointsC.length >= 6)
                            {
                                // console.log("vert:(" + i + "," + k + "," + j + ")",Separator.tempPointsC);
                                Separator.tempPointsD.push({vertices:Separator.tempPointsC.concat(),triIndex:i,col:j,row:k});
                                
                            }                                
                        }
                    }                                    
                     
                }
                len = Separator.tempPointsD.length;
                if(len > 0)
                {                       
                    let obj:any;
                    //计算uv         
                    k = len3 = newVertices.length;
                    len = Separator.tempPointsD.length;
                    for(i=0;i<len;++i)
                    {
                        obj = Separator.tempPointsD[i];  
                        // if(obj.triIndex != 0 || obj.col != 2 || obj.row != 1) 
                        // continue;
                        len2 = obj.vertices.length;
                        for(j=0;j<len2;j+=2)
                        {
                            newIndices.push(newVertices.length/2);
                            ax = obj.vertices[j];                            
                            u = (ax - obj.col*r - offsetX)/fillWidth;
                            result.uvs[k]=u;
                            newVertices[k++] = ax;
                            
                            ay = obj.vertices[j+1];
                            v = (ay - obj.row*b - offsetY)/fillHeight;
                            result.uvs[k]=v;
                            newVertices[k++] = ay;
                        }                        
                    }                                   
                }          
                result.vertices= newVertices;
                result.indices = newIndices;

                //存在矩阵变换，恢复矩阵对所有顶点的改变
                if(isMatrix)
                {
                    matrix.invert();
                    arr = newIndices;
                    len = arr.length;
                    for(i=0;i<len;i+=3)
                    {   
                        indA = arr[i]*2;
                        ax = newVertices[indA];
                        ay = newVertices[indA+1];
                        indB = arr[i+1]*2;
                        bx = newVertices[indB];
                        by = newVertices[indB+1];
                        indC = arr[i+2]*2;
                        cx = newVertices[indC];
                        cy = newVertices[indC+1];
                        
                        x = matrix.a * ax + matrix.c * ay + matrix.tx;
                        y = matrix.b * ax + matrix.d * ay + matrix.ty;
                        newVertices[indA] = x;
                        newVertices[indA+1] = y;
                        x = matrix.a * bx + matrix.c * by + matrix.tx;
                        y = matrix.b * bx + matrix.d * by + matrix.ty;
                        newVertices[indB] = x;
                        newVertices[indB+1] = y;
                        x = matrix.a * cx + matrix.c * cy + matrix.tx;
                        y = matrix.b * cx + matrix.d * cy + matrix.ty;
                        newVertices[indC] = x;
                        newVertices[indC+1] = y;
                    }
                }                
                
            }
            return result;
        }
        /**计算矩形顶点和三角形顶点的交集路径
         * @param rectPoints 矩形顶点(顺时针)
         * @param trianglePoints 三角形顶点(顺时针)
         * @param repeat 填充图形是否重复
         * @param result 结果数组
        */
        private static triangleCutRect(rectPoints:number[],trianglePoints:number[],result:number[]):number[]
        {
            let i:number,len:number;
            if(MathUtil.polygonClip(rectPoints,trianglePoints,result))
            {
                // console.log("result",result);
                //填充纹理重复平铺，则重新组装新的顶点数组(不共用顶点)
                len = result.length;
                if(len > 2 && len < 6)
                debugger;   
                for(i=4;i<len;i+=2)
                { 
                    result.push(result[0], result[1], result[i-2], result[i-1], result[i], result[i+1]);
                }
                if(len > 0)
                    result.splice(0,len);
            }
            else
            {
                result.length = 0;
            }
            // console.log("split-result",result);
            return result;            
        }
        private static tempPointsA:number[]=[];
        private static tempPointsB:number[]=[];
        private static tempPointsC:number[]=[];
        private static tempPointsD:any[]=[];        
    }
    
}